#include "var.h"
#include "object.h"
    
namespace sde {
    
    boost::python::object VarToPythonObject(Var var) {
        if (boost::any_cast<bool>(&var))
            return boost::python::object(boost::any_cast<bool>(var));
        else if (boost::any_cast<int>(&var))
            return boost::python::object(boost::any_cast<int>(var));
        else if (boost::any_cast<float>(&var))
            return boost::python::object(boost::any_cast<float>(var));
        else if (boost::any_cast<std::string>(&var))
            return boost::python::object(boost::any_cast<std::string>(var));
        else if (boost::any_cast<Vector2>(&var)) {
            Vector2 v = boost::any_cast<Vector2>(var);
            return Object::PythonVector2(v.x,v.y);
        } else if (boost::any_cast<Vector3>(&var)) {
            Vector3 v = boost::any_cast<Vector3>(var);
            return Object::PythonVector3(v.x,v.y,v.z);
        } else if (boost::any_cast<Quaternion>(&var)) {
            Quaternion q = boost::any_cast<Quaternion>(var);
            return Object::PythonQuaternion(q.w,q.x,q.y,q.z);
        } else
            return boost::python::object();
    }
    
    Var PythonObjectToVar(boost::python::object obj) {
        std::string type = boost::python::extract<std::string>(obj.attr("__class__").attr("__name__"));
        if (type == "bool") {
            bool b = boost::python::extract<bool>(obj);
            return Var(b);
        } else if (type == "int") {
            int i = boost::python::extract<int>(obj);
            return Var(i);
        } else if (type == "float") {
            float f = boost::python::extract<float>(obj);
            return Var(f);
        } else if (type == "str") {
            std::string s = boost::python::extract<std::string>(obj);
            return Var(s);
        } else if (type == "Vector2") {
            float x = boost::python::extract<float>(obj.attr("x"));
            float y = boost::python::extract<float>(obj.attr("y"));
            return Var(Vector2(x,y));
        } else if (type == "Vector3") {
            float x = boost::python::extract<float>(obj.attr("x"));
            float y = boost::python::extract<float>(obj.attr("y"));
            float z = boost::python::extract<float>(obj.attr("z"));
            return Var(Vector3(x,y,z));
        } else if (type == "Quaternion") {
            float x = boost::python::extract<float>(obj.attr("x"));
            float y = boost::python::extract<float>(obj.attr("y"));
            float z = boost::python::extract<float>(obj.attr("z"));
            float w = boost::python::extract<float>(obj.attr("w"));
            return Var(Quaternion(w,x,y,z));
        } else if (type == "tuple") {
            bool allFloats = true;
            int len = boost::python::extract<int>(obj.attr("__len__")());
            for (int i = 0; i < len && allFloats; ++i) {
                std::string iType = boost::python::extract<std::string>(obj[i].attr("__class__").attr("__name__"));
                if (iType != "float" && iType != "int")
                    allFloats = false;
            }
            if (allFloats) {
                if (len == 2) {
                    float f1 = boost::python::extract<float>(obj[0]);
                    float f2 = boost::python::extract<float>(obj[1]);
                    return Var(Vector2(f1,f2));
                } else if (len == 3) {
                    float f1 = boost::python::extract<float>(obj[0]);
                    float f2 = boost::python::extract<float>(obj[1]);
                    float f3 = boost::python::extract<float>(obj[2]);
                    return Var(Vector3(f1,f2,f3));
                } else if (len == 4) {
                    float f1 = boost::python::extract<float>(obj[0]);
                    float f2 = boost::python::extract<float>(obj[1]);
                    float f3 = boost::python::extract<float>(obj[2]);
                    float f4 = boost::python::extract<float>(obj[3]);
                    return Var(Quaternion(Degree(f1),Vector3(f2,f3,f4)));
                } else {
                    return Var();
                }
            } else {
                return Var();
            }
        } else
            return Var();
    }
    
    boost::python::dict VarMapToPythonDict(VarMap vars) {
        boost::python::dict dict;
        for (VarMap::iterator i = vars.begin(); i != vars.end(); ++i)
            dict[i->first] = VarToPythonObject(i->second);
        return dict;
    }
    
    VarMap PythonDictToVarMap(boost::python::object dict) {
        VarMap vars;
        boost::python::object items = dict.attr("items")();
        int itemCount = boost::python::extract<int>(items.attr("__len__")());
        for (int i = 0; i < itemCount; ++i)
            vars[boost::python::extract<std::string>(items[i][0])] = PythonObjectToVar(items[i][1]);
        return vars;
    }
}
